package com.htstar.ovms.device.service.impl;

import cn.hutool.core.date.DateUtil;
import com.htstar.ovms.common.core.util.ByteDataUtil;
import com.htstar.ovms.common.core.util.OvmDateUtil;
import com.htstar.ovms.device.api.constant.CommandConstant;
import com.htstar.ovms.device.api.constant.DeviceOnlineConstant;
import com.htstar.ovms.device.api.constant.ObdMethodConstant;
import com.htstar.ovms.device.api.constant.RocketMQConstant;
import com.htstar.ovms.device.api.dto.ProtoTransferDTO;
import com.htstar.ovms.device.api.entity.DeviceCommand;
import com.htstar.ovms.device.api.feign.DeviceGatewayFeign;
import com.htstar.ovms.device.api.feign.DeviceGatewayFeign;
import com.htstar.ovms.device.api.req.ObdSetGpsReq;
import com.htstar.ovms.device.api.req.ObdSettingReq;
import com.htstar.ovms.device.api.wrapper.MessageWrapper;
import com.htstar.ovms.device.api.wrapper.OTAData;
import com.htstar.ovms.device.handle.event.DeviceUpOriDataEvent;
import com.htstar.ovms.device.handle.event.ObdAlarmProcotoEvent;
import com.htstar.ovms.device.handle.event.ObdConditionProcotoEvent;
import com.htstar.ovms.device.handle.event.ObdGpsProcotoEvent;
import com.htstar.ovms.device.protoco.*;
import com.htstar.ovms.device.service.*;
import com.htstar.ovms.device.util.ObdConditionUtil;
import com.htstar.ovms.device.util.ObdUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Description: 谁被协议解析（主要解析byte[]强业务相关的处理，如果非强业务及时性靠后，可以在事件监听中处理）
 * Author: flr
 * Date: Created in 2020/6/11
 * Company: 航通星空
 * Modified By:
 */
@Service
@Slf4j
public class DeviceWrapperServiceImpl implements DeviceWrapperService {

    @Autowired
    private DeviceTripService deviceTripService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private DeviceLastDataService deviceLastDataService;

    @Autowired
    private DeviceCommandService commandService;

    @Autowired
    RocketMqSenderService rocketMqSenderService;

    @Autowired
    OTAUpdateService otaUpdateService;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    DeviceGatewayFeign deviceGatewayFeign;


    /**
     * 上下文对象
     */
    @Autowired
    private ApplicationEventPublisher publisher;

    @Override
    public MessageWrapper handlePackageWrapper(ProtoTransferDTO dto) {
        try {
            //异步数据入库
            String method = dto.getMethodName().toUpperCase();
            log.info("【设备服务收到数据包类型：{}】", method);
            if (method.equals("D005")) {
                log.info("Device-Service接收到{}类型包,数据{}", method, ObdUtil.byteArrayToHexStr(dto.getData()));
            }
//            if (method.equals("A001")) {
//                byte[] data = dto.getData();
//                System.out.println(byteArrayToHexStr(data));
//            }
            publisher.publishEvent(new DeviceUpOriDataEvent(this, dto));//原始数据入库
            //检查版本更新
            switch (method) {
                case ObdMethodConstant.LOGING_NUM://1001
                    return login(dto);

                case ObdMethodConstant.LOGIN_OUT_NUM://1002
                    return loginOut(dto);

                case ObdMethodConstant.ALARM_NUM://4007
                    return alarm(dto);

                case ObdMethodConstant.FLOW_NUM://4004
                    return flow(dto);

                case ObdMethodConstant.GPS_NUM://4001
                    return gps(dto);

                case ObdMethodConstant.CONDITION_NUM:
                    return condition(dto);

                case ObdMethodConstant.HEARTBEAT_NUM:
                    return heartbeat(dto);

                case ObdMethodConstant.SET_REPLY_NUM:
                    return setReply(dto);

                case ObdMethodConstant.GSENSOR_NUM:
                    return gsensor(dto);
//                case ObdMethodConstant.OTA_COMMAND:
//                    return otaCommand(dto);
                case ObdMethodConstant.OTA_RESULT:
                    return otaResult(dto);
                case ObdMethodConstant.SET_REPLY_CNU:
                    return alarmNum(dto);
                default:
                    log.warn("暂未解析该种类的协议，协议编号：{}", method);
                    return MessageWrapper.send(dto.getDeviceSn());
            }
        } catch (Exception e) {
            log.error("解析OBD协议异常：", e);
            return MessageWrapper.send(dto.getDeviceSn());
        }

    }

    private MessageWrapper otaResult(ProtoTransferDTO dto) {
        log.info("收到D005数据包{}", ObdUtil.byteArrayToHexStr(dto.getData()));
        String s = ObdUtil.byteArrayToHexStr(dto.getData());
        String oneByte = s.substring(0, 2);
        //非终端直接返回
        if (!"00".equals(oneByte)) {
            return null;
        }
        String rs = s.substring(2, 4);
        /**
         * =0x00表示成功
         * =0x01表示失败
         */
        if ("00".equals(rs)) {
            log.info("【升级成功，设备号{}】", dto.getDeviceSn());
            otaUpdateService.otaUpdateSuccess(dto.getDeviceSn(), 1);
            redisTemplate.delete("OTAList:" + dto.getDeviceSn());//最终删除
//            String otaNeedToList = (String) redisTemplate.opsForValue().get("OTANoOnlineList");
//            log.info("更新待升级列表前{}", otaNeedToList);
//            if (!"".equals(otaNeedToList)) {
//                String[] split = otaNeedToList.split(",");
//                List<String> strings = Arrays.asList(split);
//                strings.remove(dto.getDeviceSn());
//                if (strings.size() == 0) {
//                    redisTemplate.opsForValue().set("OTANoOnlineList", "");
//                    log.info("全部待更新设备完成更新");
//                    return null;
//                }
//                StringBuffer stringBuffer = new StringBuffer();
//                for (String string : strings) {
//                    stringBuffer.append(string).append(",");
//                }
//                String substring = stringBuffer.substring(0, stringBuffer.length());
//                redisTemplate.opsForValue().set("OTANoOnlineList", substring);
//                log.info("更新待升级列表前{}", substring);
//            }
            return null;
        }
        if ("01".equals(rs)) {//失败重试3次
            boolean retry = otaUpdateService.isRetry(dto.getDeviceSn());
            if (retry) {
                String otaData = (String) redisTemplate.opsForValue().get("OTAList:" + dto.getDeviceSn());
                MessageWrapper msgWrapper = new MessageWrapper();
                msgWrapper.setDeviceSn(dto.getDeviceSn());
                msgWrapper.setMessageType(MessageWrapper.MessageType.SEND);
                msgWrapper.setSeq(6L);
                msgWrapper.setBody(hexStrToByteArray(otaData));
                return msgWrapper;
            }
            redisTemplate.delete("OTAList:" + dto.getDeviceSn());//最终删除
        }
        return null;
    }

    private MessageWrapper otaCommand(ProtoTransferDTO dto) {
        String s = ObdUtil.byteArrayToHexStr(dto.getData());
        String oneByte = s.substring(0, 1);
        //非终端直接返回
        if (!"00".equals(oneByte)) {
            return null;
        }
        String rs = s.substring(2, 3);
        //指令接收成功
        if ("01".equals(rs)) {
            otaUpdateService.updateCommandSendStatus(dto.getDeviceSn(), 1);
        }
        return null;
    }


    /**
     * Description: 登出
     * Author: flr
     * Company: 航通星空
     */
    private MessageWrapper loginOut(ProtoTransferDTO dto) {
        log.info("设备：[{}]登出 CST{}", dto.getDeviceSn(), DateUtil.formatLocalDateTime(dto.getRevCstTime()));
        //更新在线状态
        deviceLastDataService.updateOnline(dto.getDeviceSn(), DeviceOnlineConstant.OFFLINE);
        return MessageWrapper.loginOut(dto.getDeviceSn(), null);
    }

    /**
     * @Description: GSensor数据上传
     * @Author: 范利瑞
     * @CreateDate: 2020/4/10 15:44
     */
    private MessageWrapper gsensor(ProtoTransferDTO dto) {
        log.info("设备：[{}]GSensor数据 CST{}", dto.getDeviceSn(), DateUtil.formatLocalDateTime(dto.getRevCstTime()));
        return MessageWrapper.send(dto.getDeviceSn());
    }

    /**
     * Description: 设置指令响应
     * Author: flr
     * Company: 航通星空
     */
    private MessageWrapper setReply(ProtoTransferDTO dto) {
        //收到设置回复就成功
        String s = ObdUtil.byteArrayToHexStr(dto.getData());
        log.info("【升级成功，设备号{}】", dto.getDeviceSn());
        otaUpdateService.otaUpdateSuccess(dto.getDeviceSn(), 1);
        redisTemplate.delete("OTAList:" + dto.getDeviceSn());//最终删除
        //*************
        int startIndex = 0;// 指令序号 不处理
        byte[] cmdSeqData = ByteDataUtil.bytesFromBytes(dto.getData(), startIndex, 2);
        int protocoSeq = (int) ByteDataUtil.bytesToShortLittle(cmdSeqData);
        log.info("设备：[{}]设置指令回包 CST{}，协议内指令序列号：{}", dto.getDeviceSn(), DateUtil.formatLocalDateTime(dto.getRevCstTime()), protocoSeq);

        DeviceCommand deviceCommand = commandService.getEnt(dto.getDeviceSn(), protocoSeq);
        if (null != deviceCommand) {
            Integer commandConstant = deviceCommand.getCommandConstant();
            if (null == commandConstant || commandConstant.intValue() == 0) {
                return MessageWrapper.send(dto.getDeviceSn());
            }
            switch (commandConstant.intValue()) {
                case CommandConstant
                        .GPS_SET:
                    commandService.crackGpsSetReply(deviceCommand, dto);
                    break;
                default:
                    log.warn("系统暂未添加该类型的设置回包解析");
            }
        }

        return MessageWrapper.send(dto.getDeviceSn());
    }

    /**
     * @Description: 心跳
     * @Author: 范利瑞
     * @CreateDate: 2020/4/7 11:59
     */
    private MessageWrapper heartbeat(ProtoTransferDTO dto) {
        log.info("设备：[{}]心跳 CST{}", dto.getDeviceSn(), DateUtil.formatLocalDateTime(dto.getRevCstTime()));
        // 应答类型
        byte[] type = {(byte) 0x90, (byte) 0x03};
        byte[] msg = ObdUtil.setResponseDate(dto.getDeviceSn(), type, null);

        return MessageWrapper.heartBeat(dto.getDeviceSn(), msg);
    }

    /**
     * @Description: 故障信息
     * @Author: 金柱
     * @CreateDate: 2020/4/7 11:59
     */
    private MessageWrapper fault(){

        return MessageWrapper.send( null);
    }

    /**
     * @Description: 工况 上传
     * @Author: 范利瑞
     * @CreateDate: 2020/3/27 17:47
     */
    private MessageWrapper condition(ProtoTransferDTO dto) {
        log.info("设备：[{}]工况 CST{}", dto.getDeviceSn(), DateUtil.formatLocalDateTime(dto.getRevCstTime()));
        byte[] data = dto.getData();
        String deviceSn = dto.getDeviceSn();
        int index = 0;
        ObdConditionProcoto conditionProcoto = new ObdConditionProcoto();
        conditionProcoto.setDeviceSn(deviceSn);
        conditionProcoto.setRevTime(dto.getRevCstTime());

        ObdStatDataTp obdStatDataTp = ObdUtil.crackStatDataTp(data, index);
        conditionProcoto.setObdStatDataTp(obdStatDataTp);
        index = obdStatDataTp.getIndex();

        // 采集间隔
        byte[] collecteIntervalData = ByteDataUtil.bytesFromBytes(data, index, 2);
        short collecteInterval = ByteDataUtil.bytesToShortLittle(collecteIntervalData);
        conditionProcoto.setCollecteInterval((int) collecteInterval);
        index += 2;

        // 工况类型个数
        byte[] conTypeCountData = ByteDataUtil.bytesFromBytes(data, index, 1);
        int conTypeCount = (int) conTypeCountData[0];
        conditionProcoto.setConTypeCount(conTypeCount);
        index++;

        //工况类型数组	U16[x]
        List<String> conTypeArray = new ArrayList<>();

        if (conTypeCount > 0) {
            // 循环工况类型放到数组里
            for (int i = 0; i < conTypeCount; i++) {
                byte[] conTypeData1 = ByteDataUtil.bytesFromBytes(data, index, 1);
                index++;

                byte[] conTypeData2 = ByteDataUtil.bytesFromBytes(data, index, 1);
                String conType = ByteDataUtil.bytesToHexString(ByteDataUtil.byteMerger(conTypeData2, conTypeData1));// 小端转大端
                index++;
                conTypeArray.add(conType);
            }
        }
        conditionProcoto.setConTypeList(conTypeArray);

        // 5.工况数据的包数
        byte[] conGroupCountData = ByteDataUtil.bytesFromBytes(data, index, 1);
        int conGroupCount = (int) conGroupCountData[0];
        index++;
        conditionProcoto.setConGroupCount(conGroupCount);

        // 6.每包工况数据的长度
        byte[] conGroupSizeData = ByteDataUtil.bytesFromBytes(data, index, 1);
        int conGroupSize = (int) conGroupSizeData[0];
        conditionProcoto.setConGroupSize(conGroupSize);
        index++;

        int rpm = 0; // 发动机转速： 0x210c
        int speed = 0; // 车速：0x210d
        //7.con_data	工况数据	x	x	x = con_group_count * con_group_size
        byte[] conDataByte = ByteDataUtil.bytesFromBytes(data, index, conGroupCount * conGroupSize);

        List<ConditionModel> conditionModelList = new ArrayList<>();
        // 工况数据
        int pidIndex = 0;
        for (int i = 0; i < conTypeArray.size(); i++) {
            String pid = conTypeArray.get(i);
            ConditionModel obdCondition = ObdConditionUtil.getConditionModel(pid, conDataByte, pidIndex);
            pidIndex += obdCondition.getByteLenght();
            obdCondition.setPidKey(pid);

            if (null != obdCondition.getConValue()) {
                if (i + 1 == conGroupCount) {// 把数组最后的一组数据更新到 obd_condition_last 表
                    conditionProcoto.setLastCondition(obdCondition);
                }
                if (pid.equals("210c")) {
                    rpm = Integer.parseInt(obdCondition.getConValue());
                }
                if (pid.equals("210d")) {
                    speed = Integer.parseInt(obdCondition.getConValue());
                }
                conditionModelList.add(obdCondition);
            }
        }

        conditionProcoto.setSpeed(speed);
        conditionProcoto.setRpm(rpm);
        conditionProcoto.setConditionModelList(conditionModelList);
        try {
            //发布事件入库
            publisher.publishEvent(new ObdConditionProcotoEvent(this, conditionProcoto));
        } catch (Exception e) {
            log.error("工况事件发布失败:", e);
        }

        return MessageWrapper.send(dto.getDeviceSn(), null);
    }

    /**
     * @Description: GPS 上传
     * @Author: 范利瑞
     * @CreateDate: 2020/3/27 17:47
     */
    private MessageWrapper gps(ProtoTransferDTO dto) {
        log.info("设备：[{}]GPS CST{}", dto.getDeviceSn(), DateUtil.formatLocalDateTime(dto.getRevCstTime()));
        byte[] data = dto.getData();
        ObdGpsProtoco obdGpsProtoco = new ObdGpsProtoco();
        obdGpsProtoco.setDeviceSn(dto.getDeviceSn());
        int startIndex = 0;
        byte[] flag = ByteDataUtil.bytesFromBytes(data, startIndex, 1);
        int flagS = (int) flag[0];
        if (flagS == 0) {// 常规
            obdGpsProtoco.setFlag(0);
        } else {// 补传
            obdGpsProtoco.setFlag(1);
        }
        startIndex++;

        //1	flag	GPS数据标志	U8	1	=0x00表示常规GPS数据上传
        //=0x01 表示历史GPS数据上传
        //2	stat_data	统计数据包	STAT_DATA		其中UTC_Time为采集最后一条GPS数据的时间
        //3	gpsdata	GPS数据	GPS_DATA		GPS_ITEM个数 = 终端参数中的打包个数
        //按参数设置，范围是0 ~ 30
        //无GPS模块或隐私，此条协议不需要上传
        //4	rpmdata	RPM数据	RPM_DATA		RPM_ITEM个数 = GPS_ITEM个数，范围是0 ~ 30，特别地，RPM_ITEM的值为0xFFFF表示无效转速值。

        // 获取stat_data部分数据-------------------------------------------------
        //1 last_accon_time	最近ACC点火时间	DATE_TIME	4	OBD所在车辆最近一次acc点火的时间
        ObdStatDataTp obdStatDataTp =
                ObdUtil.crackStatDataTp(data, startIndex);
        obdGpsProtoco.setObdStatDataTp(obdStatDataTp);
        startIndex = obdStatDataTp.getIndex();
        log.info("车辆点火状态" + obdGpsProtoco.getObdStatDataTp().getObdVStateTp().getFireState());
        //gpsdata	GPS数据	GPS_DATA---------------------------------------------
        ObdGpsDataTp obdGpsDataTp = ObdUtil.crackGpsDataTp(dto.getDeviceSn(), data, startIndex, dto.getRevCstTime());
        obdGpsProtoco.setObdGpsDataTp(obdGpsDataTp);
        startIndex = obdGpsDataTp.getIndex();

        if (flagS == 0 && obdGpsDataTp.getGpsCount() > 0) {
            //处理行程 TODO（也可改为异步处理）
            Integer tripId = deviceTripService.dealProcotoTrip(dto.getDeviceSn(), obdGpsDataTp, obdStatDataTp);
            log.info("历史行程{}", obdStatDataTp.getCurrentTripMileage());
            if (tripId == null) {
                log.error("------获取行程ID为null");
            }
            obdGpsProtoco.setTripId(tripId);//行程ID交给后续
        }

        //	rpmdata	RPM数据	RPM_DATA---------------------------------------------
        ObdRpmDataTp obdRpmDataTp = ObdUtil.crackRpmDataTp(data, startIndex);
        obdGpsProtoco.setObdRpmDataTp(obdRpmDataTp);

        try {
            //发布事件入库
            publisher.publishEvent(new ObdGpsProcotoEvent(this, obdGpsProtoco));
        } catch (Exception e) {
            log.error("GPS事件发布失败:", e);
        }

        return MessageWrapper.send(dto.getDeviceSn());

    }

    public static byte[] hexStrToByteArray(String str) {
        if (str == null) {
            return null;
        }
        if (str.length() == 0) {
            return new byte[0];
        }
        byte[] byteArray = new byte[str.length() / 2];
        for (int i = 0; i < byteArray.length; i++) {
            String subStr = str.substring(2 * i, 2 * i + 2);
            byteArray[i] = ((byte) Integer.parseInt(subStr, 16));
        }
        return byteArray;
    }

    public static String byteArrayToHexStr(byte[] byteArray) {
        if (byteArray == null) {
            return null;
        }
        char[] hexArray = "0123456789ABCDEF".toCharArray();
        char[] hexChars = new char[byteArray.length * 2];
        for (int j = 0; j < byteArray.length; j++) {
            int v = byteArray[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }


    /**
     * @Description: 支持的数据流类型
     * @Author: 范利瑞
     * @CreateDate: 2020/3/20 16:25
     */
    public MessageWrapper flow(ProtoTransferDTO dto) {
        log.info("设备：[{}]支持的数据流类型协议 CST{}", dto.getDeviceSn(), DateUtil.formatLocalDateTime(dto.getRevCstTime()));
        return MessageWrapper.send(dto.getDeviceSn(), null);
    }

    public MessageWrapper alarmNum(ProtoTransferDTO dto) {
        log.info("警情响应");
        ObdAlarmProtoco obdAlarmProtoco = new ObdAlarmProtoco();
        obdAlarmProtoco.setRevTime(dto.getRevCstTime());
        obdAlarmProtoco.setDeviceSn(dto.getDeviceSn());
        byte[] data = dto.getData();
        int index = 0;
        // 警情编号
        byte[] alarmNoByte = ByteDataUtil.bytesFromBytes(data, index, 4);
        // 应答类型
        byte[] type = {(byte) 0xC0, (byte) 0x07};
        byte[] msg = ObdUtil.setResponseDate(dto.getDeviceSn(), type, alarmNoByte);
//
//        MessageWrapper alarmNum = new MessageWrapper();
//        alarmNum.setDeviceSn(dto.getDeviceSn());
//        alarmNum.setMessageType(MessageWrapper.MessageType.REPLY);
//        alarmNum.setSeq(7L);
//        alarmNum.setBody(msg);
        log.info("警情指令{}", byteArrayToHexStr(msg));
        return MessageWrapper.send(dto.getDeviceSn(), msg);

    }

    /**
     * @Description: 警情上传
     * @Author: 范利瑞
     * @CreateDate: 2020/3/20 16:25
     */
    public MessageWrapper alarm(ProtoTransferDTO dto) {
        log.info("CST：{} -->设备：[{}]警情", dto.getDeviceSn(), DateUtil.formatLocalDateTime(dto.getRevCstTime()));
        ObdAlarmProtoco obdAlarmProtoco = new ObdAlarmProtoco();
        obdAlarmProtoco.setRevTime(dto.getRevCstTime());
        obdAlarmProtoco.setDeviceSn(dto.getDeviceSn());
        obdAlarmProtoco.setProtoTransferDTO(dto);
        byte[] data = dto.getData();
        int index = 0;
        // 警情编号
        byte[] alarmNoByte = ByteDataUtil.bytesFromBytes(data, index, 4);
        int alarmNo = ByteDataUtil.bytesToIntLittle(alarmNoByte);
        obdAlarmProtoco.setAlarmNo((long) alarmNo);
        index += 4;
        ObdStatDataTp obdStatDataTp = ObdUtil.crackStatDataTp(data, index);
        index = obdStatDataTp.getIndex();
        obdAlarmProtoco.setObdStatDataTp(obdStatDataTp);

        ObdGpsDataTp obdGpsDataTp = ObdUtil.crackGpsDataTp(dto.getDeviceSn(), data, index, dto.getRevCstTime());
        obdAlarmProtoco.setObdGpsDataTp(obdGpsDataTp);
        index = obdGpsDataTp.getIndex();

        // 警情个数
        byte[] alarmCountData = ByteDataUtil.bytesFromBytes(data, index, 1);
        int alarmCount = (int) alarmCountData[0];
        index++;
        obdAlarmProtoco.setAlarmCount(alarmCount);

        List<AlarmDataTp> alarmDataTpList = ObdUtil.crackAlarmDataTp(alarmCount, data, index);
        obdAlarmProtoco.setAlarmDataTpList(alarmDataTpList);
//        for (AlarmDataTp alarmDataTp : obdAlarmProtoco.getAlarmDataTpList()) {
//            System.out.println("警情阈值"+alarmDataTp.getAlarmThreshold());
//            System.out.println("当前值"+alarmDataTp.getAlarmDesc());
//            System.out.println("警情类型"+alarmDataTp.getAlarmType());
//        }
        //发布警情时间监听
        try {
            publisher.publishEvent(new ObdAlarmProcotoEvent(this, obdAlarmProtoco));
        } catch (Exception e) {
            log.error("发布警情的异步时间监听错误：", e);
        }
//        点火时初始时化设备
        for (AlarmDataTp rs : obdAlarmProtoco.getAlarmDataTpList()) {
            if (rs.getAlarmType().intValue() == 22) {
                String deviceSn = dto.getDeviceSn();
                Boolean isWaitingOTA = redisTemplate.hasKey("OTAList:" + deviceSn);
                if (isWaitingOTA) {//是否为待升级设备
                    String OTAData = (String) redisTemplate.opsForValue().get("OTAList:" + deviceSn);
                    OTAData otaData22 = new OTAData();
                    otaData22.setData(OTAData);
                    ArrayList<String> sn = new ArrayList<>();
                    sn.add(dto.getDeviceSn());
                    otaData22.setDeviceSnList(sn);
                    try {//下发命令
                        ///GPS指令消息下发
                        MessageWrapper obdGpsMsg = new MessageWrapper();
                        obdGpsMsg.setDeviceSn(dto.getDeviceSn());
                        obdGpsMsg.setMessageType(MessageWrapper.MessageType.SEND);
                        obdGpsMsg.setSeq(6L);
//                obdGpsMsg.setBody(hexStrToByteArray("40409C000331333432343235353731320000000000000000005004006674703A2F2F746573743A746573743132334035382E36302E302E36302F4944442D3231334C2F4944442D3231334C5F42332E322E302E315F32303230313232335F30312E74623B636D6E65743B686368656E3B3132333B3132312E31352E372E34343B32313B303030313B56312E302E303B56312E302E303B3130E6670D0A"));
                        //------------注意：时间间隔已在底方法写死，这里的设置值无效-------------
//                        ObdSettingReq obdSettingReq = new ObdSettingReq();
//                        obdSettingReq.setDeviceSn(dto.getDeviceSn());
//                        obdSettingReq.setConditionUpTimeInterval(10);
//                        obdSettingReq.setSleepUpTimeInterval(60);
//                        obdSettingReq.setGpsUpTimeInterval(10);
//                        byte[] setting = ObdUtil.getObdSettingCommandByte(obdSettingReq, 7L);//这里应该用唯一ID
                        byte[] setting = hexStrToByteArray(OTAData);
                        obdGpsMsg.setBody(setting);
                        log.info("setting消息下发，data={}", byteArrayToHexStr(setting));
                        return obdGpsMsg;
//                        deviceGatewayFeign.updateBatch(otaData22);//通过接口下发
//                        redisTemplate.delete("OTAList:" + deviceSn); //成功或失败超过3次才删除
                    } catch (Exception e) {
                        log.error("点火时OTA升级下发错误，设备号{}", deviceSn);
                    }
                } else {
                    break;
                }
            }
//            if (rs.getAlarmType().intValue() == 22) {
//                //延时下发升级指令
//                String otaNeedToList = (String) redisTemplate.opsForValue().get("OTANoOnlineList");
//                String otaData = (String) redisTemplate.opsForValue().get("OTAData");
//                log.info("不在线设备表{}，升级数据{}", otaNeedToList, otaData);
//                String[] split = otaNeedToList.split(",");
//                List<String> deviceList = Arrays.asList(split);
//                boolean contains = deviceList.contains(dto.getDeviceSn());
//                if (!contains) {//不在待升级设备跳过
//                    return MessageWrapper.send(dto.getDeviceSn());
//                }
//                //从待升级设备中移除
//                String replace = otaNeedToList.replace(dto.getDeviceSn(), "");
//                String[] split1 = replace.split(",");
//                List<String> strings = Arrays.asList(split1);
////                Iterator<String> iterator = deviceList.iterator();
////                while (iterator.hasNext()) {
////                    String next = iterator.next();
////                    if (dto.getDeviceSn().equals(next)) {
////                        iterator.remove();
////                    }
////                }
//                StringBuffer stringBuffer = new StringBuffer();
//                for (String deviceSn : strings) {
//                    stringBuffer.append(deviceSn).append(",");
//                }
//                String s = stringBuffer.toString();
//                String substring = s.substring(0, s.length() - 1);
//                redisTemplate.opsForValue().set("OTANoOnlineList", substring);
//                log.info("更新不在线设备表{}", substring);
//                OTAData otaData1 = new OTAData();
//                otaData1.setData(otaData);
//                ArrayList<String> sn = new ArrayList<>();
//                sn.add(dto.getDeviceSn());
//                otaData1.setDeviceSnList(sn);
//                deviceGatewayFeign.updateBatch(otaData1);
//                log.info("设备号{},数据{}延时任务结束", dto.getDeviceSn(), otaData);
//                //创建延时任务
////                log.info("延时任务开始");
////                Timer timer = new Timer();// 实例化Timer类
////                timer.schedule(new TimerTask() {
////                    public void run() {
////                        OTAData otaData1 = new OTAData();
////                        otaData1.setData(otaData);
////                        ArrayList<String> sn = new ArrayList<>();
////                        sn.add(dto.getDeviceSn());
////                        otaData1.setDeviceSnList(sn);
////                        deviceGatewayFeign.updateBatch(otaData1);
////                        log.info("设备号{},数据{}延时任务结束", dto.getDeviceSn(), otaData);
////                        this.cancel();
////                    }
////                }, 10 * 1000);// 这里百毫秒
//
//
//                //二
////                Thread daemonThread = new Thread(new Runnable() {
////                    public void run() {
////                        long l = System.currentTimeMillis();
////                        // Repeat forever
////                        boolean stop = false;
////                        while (!stop) {
////                            if (System.currentTimeMillis() - l > 1000 * 10) {
////                                stop = true;
////                                System.out.println("延时执行");
////                            }
////                        }
////                    }
////                });
////                daemonThread.setDaemon(true);
////                daemonThread.start();
////                ///GPS指令消息下发
////                MessageWrapper obdGpsMsg = new MessageWrapper();
////                obdGpsMsg.setDeviceSn(dto.getDeviceSn());
////                obdGpsMsg.setMessageType(MessageWrapper.MessageType.SEND);
////                obdGpsMsg.setSeq(6L);
//////                obdGpsMsg.setBody(hexStrToByteArray("40409C000331333432343235353731320000000000000000005004006674703A2F2F746573743A746573743132334035382E36302E302E36302F4944442D3231334C2F4944442D3231334C5F42332E322E302E315F32303230313232335F30312E74623B636D6E65743B686368656E3B3132333B3132312E31352E372E34343B32313B303030313B56312E302E303B56312E302E303B3130E6670D0A"));
////                //------------注意：时间间隔已在底方法写死，这里的设置值无效-------------
////                ObdSettingReq obdSettingReq = new ObdSettingReq();
////                obdSettingReq.setDeviceSn(dto.getDeviceSn());
////                obdSettingReq.setConditionUpTimeInterval(10);
////                obdSettingReq.setSleepUpTimeInterval(60);
//////                obdSettingReq.setGpsUpTimeInterval(10);
////                byte[] setting = ObdUtil.getObdSettingCommandByte(obdSettingReq, 7L);//这里应该用唯一ID
////                obdGpsMsg.setBody(setting);
////                log.info("setting消息下发，data={}", byteArrayToHexStr(setting));
////                return obdGpsMsg;
//            }
        }
        // 应答类型
        byte[] type = {(byte) 0xC0, (byte) 0x07};
        byte[] msg = ObdUtil.setResponseDate(dto.getDeviceSn(), type, alarmNoByte);

//        MessageWrapper alarmNum = new MessageWrapper();
//        alarmNum.setDeviceSn(dto.getDeviceSn());
//        alarmNum.setMessageType(MessageWrapper.MessageType.REPLY);
//        alarmNum.setSeq(7L);
//        alarmNum.setBody(msg);
        log.info("警情指令{}", byteArrayToHexStr(msg));
        return MessageWrapper.send(dto.getDeviceSn(), msg);
    }

    /**
     * @Description: 设备登入处理
     * @Author: 范利瑞
     * @CreateDate: 2020/3/20 16:25
     */
    public MessageWrapper login(ProtoTransferDTO dto) {
        log.info("CST：{} -->设备：[{}]登入", dto.getDeviceSn(), DateUtil.formatLocalDateTime(dto.getRevCstTime()));
        // 获取StatData部分数据
        int index = 0;
        ObdStatDataTp obdStatDataTp = ObdUtil.crackStatDataTp(dto.getData(), index);

        log.debug("obdStatDataTp-->{}", obdStatDataTp);
        // IP
        byte[] ipaddress = {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
        // 端口
        byte[] port = {0x00, 0x00};
        // 时间戳
        int t = (int) (System.currentTimeMillis() / 1000);
        byte[] time = ByteDataUtil.toPrimitives(ByteDataUtil.intToBytesLittle(t));
        // 全部内容
        byte[] content = ByteDataUtil.byteMerger(ByteDataUtil.byteMerger(ipaddress, port), time);
        // 应答类型
        byte[] type = {(byte) 0x90, (byte) 0x01};
        byte[] msg = ObdUtil.setResponseDate(dto.getDeviceSn(), type, content);

        //检测是否是允许连接的设备
        Integer deviceId = deviceService.getAllowStatus(dto.getDeviceSn());
        if (deviceId == null) {
            return MessageWrapper.refuseLogin(dto.getDeviceSn(), msg);
        }
        // 回复指令
        return MessageWrapper.login(dto.getDeviceSn(), msg);
    }


    /**
     * device-gateway下发命令失败
     *
     * @param otaData
     */
    @Override
    public void OTAupdateState(OTAData otaData) {
//        otaUpdateService.updateFailureTime(otaData);
        ArrayList<String> objects = new ArrayList<>();
        objects.add(otaData.getDeviceSn());
        deviceService.OTAfaild(otaData.getDeviceSn());//2失败
    }

}
